package com.maddox.libnavcompiler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.auto.service.AutoService;
import com.maddox.libnavannotation.ActivityDestination;
import com.maddox.libnavannotation.FragmentDestination;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;

/**
 * 解析收集app项目中自定义注解的导航信息
 *
 * @AutoService: 在构建项目的时候会自动执行该注解编译类
 * @SupportedSourceVersion: 支持的jdk版本
 * @SupportedAnnotationTypes: 声明该注解处理器处理的注解类型
 */
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"com.maddox.libnavannotation.ActivityDestination", "com.maddox.libnavannotation.FragmentDestination"})
public class NavProcessor extends AbstractProcessor {
    //java日志打印
    private Messager messager;
    //文件创建辅助类
    private Filer filer;
    //输出的文件名
    private static final String OUT_FILE_NAME = "destination.json";

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        //获取日志打印工具
        messager = processingEnvironment.getMessager();
        //文件处理工具
        filer = processingEnvironment.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        //通过注解处理器的上下文环境,获取指定注解类型的注解类信息(ActivityDestination,FragmentDestination)
        Set<? extends Element> activityElements = roundEnvironment.getElementsAnnotatedWith(ActivityDestination.class);
        Set<? extends Element> fragmentElements = roundEnvironment.getElementsAnnotatedWith(FragmentDestination.class);
        //当存在有以上两种注解的信息时进行处理
        if (!activityElements.isEmpty() || !fragmentElements.isEmpty()) {
            //保存注解信息
            HashMap<String, JSONObject> destMap = new HashMap<>();
            //对标记指定的两种注解的类型进行处理,获取对应的导航信息
            handleDestination(fragmentElements, FragmentDestination.class, destMap);
            handleDestination(activityElements, ActivityDestination.class, destMap);
            FileOutputStream fos = null;
            OutputStreamWriter osw = null;

            try {
                /**
                 * 将注解获取的页面导航信息写入到/app/src/main/assets/目录下
                 * StandardLocation.CLASS_OUTPUT:->表示app/build/intermediates/javac/debug/classes/目录下
                 * StandardLocation.SOURCE_OUTPUT:->表示app/build/generated/source/apt/目录下
                 */
                FileObject resource = filer.createResource(StandardLocation.CLASS_OUTPUT, "", OUT_FILE_NAME);
                String resourcePath = resource.toUri().getPath();
                messager.printMessage(Diagnostic.Kind.NOTE, "输出路径:resourcePath->" + resourcePath);
                //对文件路径进行截取,组装成/app/src/main/assets/
                String appPath = resourcePath.substring(0, resourcePath.indexOf("app") + 4);// /app/
                String assetsPath = appPath + "src/main/assets/";// /app/src/main/assets/
                File file = new File(assetsPath);
                if (!file.exists())
                    file.mkdirs();
                File outPutFile = new File(assetsPath, OUT_FILE_NAME);
                //对于输出的json文件每当重新构建都要删除并重新创建,防止内容覆盖多余
                if (outPutFile.exists())
                    outPutFile.delete();
                outPutFile.createNewFile();

                String content = JSON.toJSONString(destMap);
                fos = new FileOutputStream(outPutFile);
                osw = new OutputStreamWriter(fos);
                osw.write(content);
                osw.flush();

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (osw != null) {
                    try {
                        osw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }


        }

        return false;
    }

    private void handleDestination(Set<? extends Element> elements, Class<? extends Annotation> clzz, HashMap<String, JSONObject> destMap) {

        for (Element element : elements) {
            //TypeElement是Element的一种,代表类型信息,因为我们的注解只标注在类上,可以直接强转
            TypeElement typeElement = (TypeElement) element;
            //获取注解的类的全路径类名
            String className = typeElement.getQualifiedName().toString();
            //根据全类名生成唯一代表该页面的id
            int id = Math.abs(className.hashCode());
            //页面跳转pageUrl
            String pageUrl = null;
            //是否需要登录
            boolean needLogin = false;
            //是否作为导航页面的默认页
            boolean asStarter = false;
            //标记当前是Fragment还是Activity
            boolean isFragment = false;

            Annotation annotation = element.getAnnotation(clzz);
            if (annotation instanceof ActivityDestination) {
                ActivityDestination destination = (ActivityDestination) annotation;
                pageUrl = destination.pageUrl();
                needLogin = destination.needLogin();
                asStarter = destination.asStarter();
                isFragment = false;
            } else if (annotation instanceof FragmentDestination) {
                FragmentDestination destination = (FragmentDestination) annotation;
                pageUrl = destination.pageUrl();
                needLogin = destination.needLogin();
                asStarter = destination.asStarter();
                isFragment = true;

            }

            if (destMap.containsKey(pageUrl)) {
                messager.printMessage(Diagnostic.Kind.ERROR, "不同的导航页面不能使用相同的pageUrl" + className);
            } else {
                JSONObject object = new JSONObject();
                object.put("id", id);
                object.put("pageUrl", pageUrl);
                object.put("needLogin", needLogin);
                object.put("asStarter", asStarter);
                object.put("className", className);
                object.put("isFragment", isFragment);
                destMap.put(pageUrl, object);
            }


        }

    }
}
